<?

/**
 * This collection of functions (libary) is licensed under GPL2.
 * See LICENSE or www.gnu.org for more details.
 *  @author Jyry Kuukkanen
 *  @copyright Jyry Kuukkanen
 */

include_once("soset.php");
include_once("sodebug.php");

/** Name array list.
 *  Extended soSet where every item is an array of values.
 */
class soArraySet extends soSet {

    /** Constructor
     *  Calls soSet constructor
     */
    function soArraySet() {
        $this->soSet();
    } // soArraySet


    /** Checks given rowno validity for an array.
     *  @param array/any $Item Array to check row no. against.
     *  @param int $RowNo Row no. to check.
     *  @param int $LowLimit Low row no. limit. Setting this to, say -1, would
     *      would cause -1 row no. to be accepted, too.
     *  @return bool Returns true(1) if row no. valid, otherwise false(0).
     *  @package soarrayset
     */
    function __checkRowNo($Item, $RowNo, $LowLimit = 0) {
        if (($RowNo < $LowLimit) || ($this->Error) ||
            ($RowNo >= count($Item))) {
            $result = 0;
        } else {
            $result = 1;
        };
        return $result;
    } // __checkRowNo


    /** Returns or initialises an item array
     *  If item requested does not contain an array, then this initialises it.
     *  @param string $Key Item id
     *  @return array/any Returns an array with values or an empty array for a new
     *      or invalid (non-array) item.
     *  @package soarrayset
     */
    function __getItem($Key) {
        $result = $this->getItem($Key);
        if (gettype($result) != "array") {
            $result = array();
        };

        return $result;
    } // __getitem


    /** Finds a row no. of an array item.
     *  Tries to find a value in column and return it's row no.
     *  @param string $Key Item name.
     *  @param any $Value Value to find.
     *  @return int Row pos of 1st row containing the value or -1 when not
     *      found (value or item).
     */
    function findArrayItem($Key, $Value) {
        $item = $this->__getItem($Key);
        if ($this->__Error) return -1; // <-- EXIT
        
        return soArrayFind($item, $Value, 1);
    } // findArrayItem


    /** Returns a value from specified item row.
     *  @param string $Key The name of a item
     *  @param int $RowNo Index of the row to get.
     *  @return string The asked value or NULL in case of error
     *  @package soarrayset
     */
    function getArrayItem($Key, $RowNo) {
        $result = $this->__getItem($Key);
        if (!$this->__checkRowNo($result, $RowNo)) return NULL; // <-- EXIT

        return $result[$RowNo];
    } // getArrayItem


    /** Stores a value for specified item row.
     *  @param string $Key Item id
     *  @param int $RowNo Item row no., -1 == as last item
     *  @param string $Value A value to store
     *  @return bool True if all ok. Otherwise false.
     */
    function setArrayItem($Key, $RowNo, $Value) {
        $result = $this->__getItem($Key);
        if ($this->Error) {
            $result = array();
            $this->Error = 0;
        };
        /* Check that the row number is valid */
        $rcount = count($result);
        if ($RowNo == -1) $RowNo = $rcount;

        $result[$RowNo] = $Value;
        $this->setItem($Key, $result);

        return 1;
    } // setArrayItem


    /** Deletes a value at specified item row.
     *  @param string $Key The name of a item
     *  @param int $RowNo Index of the row to delete.
     *  @return bool Returns true(1) if item id and rowno are valid, otherwise
     *      false(0).
     *  @package soarrayset
     */
    function delArrayItem($Key, $RowNo) {
        $result = $this->__getItem($Key);

        /* Check that column name was found and the row number is valid */
        if (($RowNo < 0) || (!$this->Error) ||
            ($RowNo >= count($result))) return NULL; // <-- EXIT!!

        return $result[$RowNo];
    } // delArrayItem


    /** Get a row from the set
     * Get the values for asked columns. If some column has not enough rows
     * The value of the column is set to an empty string "". All row numbers
     * that are below the amount of rows in the longest column
     * are accepted.
     * @param int $Row The number of the row to get
     * @param array/str $Cols Columns which value to get. If an empty array
     *                        get all columns in the set.
     * @return array/any Values for each column or NULL if error
     */
    function getRow($Row, $Cols = array()) {
        /* If columns not given, Get all of them */
        if (!count($Cols))
            $Cols = $this->getKeys();

        $row_count = $this->getRowCount($Cols, 1);
        if ($Row >= $row_count) return NULL;    // <-- EXIT!!

        $result = array();
        foreach ($Cols as $col_name)  {
            if ($Row >= $this->getRowCount(array($col_name))) {
                $value = "";
            } else {
                $value = $this->getArrayItem($col_name, $Row);
            } // if
            $result[] = $value;
        } // foreach

        return $result;
    } // getRow


    /** Get max/min/quick row count of a group of items in set.
     *  Returns a number of rows in specified items.
     *  @param array/string $Keys Array of item ids. An empty array equals
     *      all items.
     *  @param bool $Type When 0, returns the rowcount from the first column in
     *      group (quick count when it is certain that all items have the same
     *      count), otherwise loops through all columns and returns either
     *      tallest (Type=1) or shortest (Type=-1) of them.
     *  @return int Returns the number of rows or -1 on error.
     *  @package soarrayset
     */
    function getRowCount($Keys = array(), $Type = 0) {
        if (gettype($Keys) != "array") return -1; // <-- EXIT
        if (!count($Keys)) $Keys = $this->getKeys();
        $icount = count($Keys);

        if ($Type == 0) $icount = min($icount, 1);

        for ($i = 0; $i < $icount; $i++) {
            $rows = $this->__getItem($Keys[$i]);
            $new_count = count($rows);
            if ($i == 0) $result = $new_count;
            switch ($Type) {
                case $Type = 1:
                    if ($new_count > $result) $result = $new_count;
                    break;
                case $Type = -1:
                    if ($new_count < $result) $result = $new_count;
                    break;
            }; // switch
        }; // for

        return $result;
    } // getRowCount


    /** Encodes the set to a URL string.
     *  Encodes the set so that each element are URL encoded and returns them
     *  as a string where each element is delimited by delimiter string.
     *  Example:  if the set has items a=";" and b="aA", then encode("&") would
     *  @param string $Delim Delimiter string to delimit each element from another.
     *      When specifying $Delim, make sure it is one of the special URL coded
     *      characters such as "&", so that it makes a difference as a delimiter.
     *  @return string URL encoded set.
     *      return "%3B&aA".
     *  @package soarrayset
     */
    function encode($Delim = "&") {
        $result = "";

        $icount = count($this->Keys);
        for ($i = 0; $i < $icount; $i++) {
            $result = soJoinStr($result, $Delim, $this->Keys[$i]."=".
                                soUrlEncodeArray($this->Values[$i]), 1);
        }; // for

        return $result;
    } // encode


    /** Decodes a URL encoded set back from string.
     *  Decodes each special delimiter delimited sub-string in input string and 
     *  imports them to the set. 
     *  @param string $InStr URL string to decode.
     *  @param string $Delim Delimiter used in the input string to delimit items from
     *      another.
     *  @param bool $Replace When set(1), all existing items are replaced by new,
     *      otherwise imported buplicates are skipped.
     *  @package soarrayset
     */
    function decode($InStr, $Delim = "&", $Replace = 1) {
        $in_array = soExplode($InStr, $Delim);
        $tmp_array = array();
        $keys = array_keys($in_array);
        foreach ($keys as $key) {
            $split = soSplitStr($InArray[$key], "=", 1, 0);
            if (count($split) && ($split[0] != "")) {
                $tmp_array[$split[0]] = $split[1];
            }; // if
        }; // foreach
        $this->decodeArray($tmp_array, $Replace);
    } // decode


    /** Decodes an URL encoded values in an array.
     *  Works the very same way as decode(), but takes in an array to where an
     *  URL string has already been split into, like in $HTTP_GET_VARS.
     *  @param array/string $InArray Input array with URL encoded values
     *  @param bool $Replace When set(1), all existing items are replaced by new,
     *      otherwise imported buplicates are skipped.
     *  @package soarrayset
     */
    function decodeArray(&$InArray, $Replace = 1) {
        if ((gettype($InArray) != "array") ||
            !count($InArray)) return; // <-- EXIT

        $keys = array_keys($InArray);
        foreach ($keys as $key) {
            $this->setItem($key, soUrlDecodeArray($InArray[$key]));
        }; // foreach
    } // decodeArray

}; // soArraySet

?>
